[AWS Glue]データカタログのパーティションをAWS CLIで更新してみた
こんにちは、CX事業本部の若槻です。
AWS Glueでは、パーティション分割を行うことによりデータの整理や効率的なクエリ実行を行うことが可能です。
今回は、AWS GlueのデータカタログのパーティションをAWS CLIで更新してみました。
やってみた
環境準備
CloudFormationスタックをデプロイします。これによりyear
、month
、day
のパーティションキーを持ったデータカタログテーブルを作成します。
AWSTemplateFormatVersion: '2010-09-09' Resources: DevicesRawDataBucket: Type: AWS::S3::Bucket Properties: BucketName: !Sub devices-raw-data-${AWS::AccountId}-${AWS::Region} DevicesDataAnalyticsGlueDatabase: Type: AWS::Glue::Database Properties: CatalogId: !Ref AWS::AccountId DatabaseInput: Name: devices_data_analystics DevicesRawDataGlueTable: Type: AWS::Glue::Table Properties: CatalogId: !Ref AWS::AccountId DatabaseName: !Ref DevicesDataAnalyticsGlueDatabase TableInput: Name: devices_raw_data TableType: EXTERNAL_TABLE Parameters: has_encrypted_data: false serialization.encoding: utf-8 EXTERNAL: true StorageDescriptor: OutputFormat: org.apache.hadoop.hive.ql.io.HiveIgnoreKeyTextOutputFormat Columns: - Name: device_id Type: string - Name: timestamp Type: bigint - Name: state Type: boolean InputFormat: org.apache.hadoop.mapred.TextInputFormat Location: !Sub s3://${DevicesRawDataBucket}/raw-data SerdeInfo: Parameters: paths: "device_id, timestamp, state" SerializationLibrary: org.apache.hive.hcatalog.data.JsonSerDe PartitionKeys: - Name: year Type: string - Name: month Type: string - Name: day Type: string DevicesAthenaWorkGroup: Type: AWS::Athena::WorkGroup Properties: Name: devices-athena-work-group WorkGroupConfiguration: ResultConfiguration: OutputLocation: !Sub s3://${DevicesRawDataBucket}/athena-query-result EnforceWorkGroupConfiguration: true PublishCloudWatchMetricsEnabled: true
% aws cloudformation deploy \ --template-file template.yaml \ --stack-name devices-data-analytics-stack \ --capabilities CAPABILITY_NAMED_IAM \ --no-fail-on-empty-changeset
以降のコマンド実行で使用する変数を定義します。
% AWS_REGION=ap-northeast-1 % ACCOUNT_ID=$(aws sts get-caller-identity | jq -r ".Account") % RAW_DATA_BUCKET=s3://devices-raw-data-${ACCOUNT_ID}-${AWS_REGION} % GLUE_DATABASE_NAME=devices_data_analystics % GLUE_TABLE_NAME=devices_raw_data
パーティションとなるパスを持つデータをS3バケットに作成します。
{"device_id": "3ff9c44a", "timestamp": 1609348014, "state": true}
% aws s3 cp raw-data.json \ ${RAW_DATA_BUCKET}/raw-data/year=2021/month=01/day=06/raw-data.json
この時点ではデータカタログにパーティションはまだ作成されていません。
% aws glue get-partitions \ --database-name ${GLUE_DATABASE_NAME} \ --table-name ${GLUE_TABLE_NAME} { "Partitions": [] }
athena start-query-execution
コマンドによる方法
athena start-query-execution
コマンドでMSCK REPAIR TABLE
クエリを実行する方法でパーティションを更新してみます。
% aws athena start-query-execution \ --query-string "MSCK REPAIR TABLE ${GLUE_TABLE_NAME}" \ --work-group devices-athena-work-group \ --query-execution-context Database=${GLUE_DATABASE_NAME},Catalog=AwsDataCatalog
パーティション一覧を取得すると、パーティションが作成されていますね。
% aws glue get-partitions \ --database-name ${GLUE_DATABASE_NAME} \ --table-name ${GLUE_TABLE_NAME} { "Partitions": [ { "Values": [ "2021", "01", "06" ], "DatabaseName": "devices_data_analystics", "TableName": "devices_raw_data", "CreationTime": "2021-01-06T21:29:24+09:00", "LastAccessTime": "1970-01-01T09:00:00+09:00", "StorageDescriptor": { "Columns": [ { "Name": "device_id", "Type": "string" }, { "Name": "timestamp", "Type": "bigint" }, { "Name": "state", "Type": "boolean" } ], "Location": "s3://devices-raw-data-XXXXXXXXXXXX-ap-northeast-1/raw-data/year=2021/month=01/day=06", "InputFormat": "org.apache.hadoop.mapred.TextInputFormat", "OutputFormat": "org.apache.hadoop.hive.ql.io.HiveIgnoreKeyTextOutputFormat", "Compressed": false, "NumberOfBuckets": 0, "SerdeInfo": { "SerializationLibrary": "org.apache.hive.hcatalog.data.JsonSerDe", "Parameters": { "paths": "device_id, timestamp, state" } }, "BucketColumns": [], "SortColumns": [], "Parameters": {}, "StoredAsSubDirectories": false } } ] }
その他の方法
glue create-partition
やglue batch-create-partition
コマンドでもパーティションの作成は可能です。ただし前述の方法とは異なり、作成したいパーティションの仕様を明示的に指定する必要があります。
- create-partition — AWS CLI 1.18.209 Command Reference
- batch-create-partition — AWS CLI 1.18.209 Command Reference
オブジェクトが一つも作成されていない場合
S3バケットのデータロケーションにオブジェクトが一つも作成されていない場合、MSCK REPAIR TABLE
クエリは失敗します。
先程S3バケットに作成したオブジェクトを削除します。
% aws s3 rm \ ${RAW_DATA_BUCKET}/raw-data/year=2021/month=01/day=06/raw-data.json
athena start-query-execution
コマンドでパーティションを更新するクエリを実行します。
% aws athena start-query-execution \ --query-string "MSCK REPAIR TABLE ${GLUE_TABLE_NAME}" \ --work-group devices-athena-work-group \ --query-execution-context Database=${GLUE_DATABASE_NAME},Catalog=AwsDataCatalog { "QueryExecutionId": "949737b5-2514-4dd2-abf6-c997d8f5143e" }
クエリの実行結果を取得すると、Tables missing on filesystem:\tdevices_raw_data
というエラーとなっています。
% aws athena get-query-results \ --query-execution-id 949737b5-2514-4dd2-abf6-c997d8f5143e { "ResultSet": { "Rows": [ { "Data": [ { "VarCharValue": "Tables missing on filesystem:\tdevices_raw_data" } ] } ], "ResultSetMetadata": { "ColumnInfo": [] } }, "UpdateCount": null
そもそもオブジェクトをすべて削除する状況があまり無いですし、その状況になったとしてパーティション更新がエラーになったからと言ってすぐに困ることは無いですが、私はこの検証を行う際にバケットにデータを上げ忘れたままパーティション更新を行おうとして今回のエラーが出たため、「なんでテーブルが無いなんて言ってるんだ?」と少し混乱しました。
おわりに
AWS GlueのデータカタログのパーティションをAWS CLIで更新してみました。
Glueで構築したETLシステムにおいてはパーティション更新はクローラーやLambdaで行うことが多いと思いますが、これを応用すればGlueジョブの中でBoto3を使ってジョブ冒頭でパーティション更新させて構成を単純化させる、なんてこともできそうですね。
参考
- Demystifying the ways of creating partitions in Glue Catalog on partitioned S3 data for faster insights | by Subhash Burramsetty | Medium
- AWS Glueデータカタログへのテーブルの作成とAthenaの設定をCloudFormationでやってみた | Developers.IO
- get-query-results — AWS CLI 1.18.209 Command Reference
- rm — AWS CLI 1.18.209 Command Reference
以上